import { io } from "socket.io-client";

class SocketManager {
    constructor() {
        this.socket = null;
        this.timeout = 5000;
    }

    init(serverAddress, onConnect, onDisconnect) {
        console.log('#socket -> init: ' + serverAddress);
        this.socket = io(serverAddress);
        this.socket.on('connect', () => {
            console.log('#socket -> connect');
            onConnect && onConnect();
        });
        this.socket.on('disconnect', () => {
            console.log('#socket -> disconnect');
            onDisconnect && onDisconnect();
        });
        // this._test();
        // this.socket.on('hi', (data) => {
        //     console.log('#hi -> ' + data);
        // });
    }

    close() {
        this.socket && this.socket.close();
    }

    _check() {
        if (this.socket && this.socket.connected) {
            return true;
        } else {
            console.error('#socket check failed');
            return false;
        }
    }

    // only for test
    _test() {
        setInterval(() => {
            // socketManager.emitWithAck(
            //     "test",
            //     ["world", 1, 2, 3],
            //     (response) => {
            //         console.log('response: ' + response);
            //     }
            // );
            // socketManager.emitWithAck(
            //     "test",
            //     { name: "liuming", age: 32 },
            //     (response) => {
            //         console.log('response: ' + response);
            //     }
            // );
            // socketManager.emit("AudioHelper", "id", { name: "liuming", age: 34 })

            // socketManager.emitWithAck(
            //     "test",
            //     { name: "liuming", age: 32 },
            //     (response) => {
            //         console.log('response: ' + response);
            //     }
            // );
        }, 2000);
    }

    /**
     * 通过 socket 发送数据到 server：只执行一次；超时报错
     * ack(acknowledgement): 表示确认或接收确认，因此只被调用一次
     * 一旦调用了 ack 回调函数，它将被标记为已被调用，后续的调用将被忽略。
     * 服务器端想多次调用，可以多次 emit 数据到 web 端
     * @param {*} eventName 
     * @param {*} args 可以是：[1, 2 ,3], {name: "liuming", age: 32}
     * @param {*} ack 
     */
    async emitWithAck(eventName, args, ack) {
        if (this._check()) {
            try {
                const response = await this.socket.timeout(this.timeout).emitWithAck(eventName, args);
                ack && ack(response)
            } catch (err) {
                // the server did not acknowledge the event in the given delay
                console.error('#socket response timeout: ' + err);
            }
        }
    }

    emit(eventName, ...args) {
        this.socket && this.socket.connected && this.socket.emit(eventName, ...args);
    }

    on(eventName, listener) {
        this.socket && this.socket.connected && this.socket.on(eventName, listener);
    }

    /**
     * example:
     * 1. remove specific listener:
     * socket.on("my-event", myListener);
     * socket.off("my-event", myListener);
     * 2. remove all listeners for that event:
     * socket.off("my-event");
     * 3. remove all listeners for all events:
     * socket.off();
     * @param {*} eventName 
     * @param {*} listener 
     */
    off(eventName, listener) {
        this.socket && this.socket.connected && this.socket.off(eventName, listener);
    }

    __once(eventName, callback) {
        this.socket && this.socket.connected && this.socket.once(eventName, callback);
    }

    // remove all listeners for that event
    __off(eventName) {
        this.socket.off(eventName)
    }
}

const socketManager = new SocketManager();

export default socketManager;